import { UserService, UserStorage } from '@2/app/core/ioc';
import { AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import { RequestOptions, Result } from '#/axios';
import { useI18n } from '@/hooks/web/useI18n';
import { useMessage } from '@/hooks/web/useMessage';
import { ResultEnum } from '@/enums/httpEnum';
import { AUTHORIZATION } from '@2/typings/constant/api.c';
import { CreateAxiosOptions } from '@/utils/http/axios/axiosTransform';
import { IGNORE_RESOURCES } from '@2/typings/http.d';

const { createMessage, createErrorModal } = useMessage();

/**
 * @program: microservice-central-portal
 * @description: HTTP 访问请求拦截器
 * @author: baiHoo.chen
 * @create: 2022年5月24日
 **/
export default class HttpInterceptor {
  /**
   * @description: 请求拦截器处理
   */
  public static setAuthorization(config: InternalAxiosRequestConfig, options: CreateAxiosOptions) {
    // 请求之前处理config
    const token = UserStorage.getToken()?.token;
    if (token && (config as Recordable)?.requestOptions?.withToken !== false) {
      options.authenticationScheme = 'Bearer';
      (config as Recordable).headers[AUTHORIZATION] = options.authenticationScheme
        ? `${options.authenticationScheme} ${token}`
        : token;
    }
    return config;
  }

  /**
   * 处理已完成请求后的数据。如果数据不是预期格式，可直接抛出错误
   * @param res 响应结果 {@link AxiosResponse @link Result}
   * @param options
   */
  public static requestedTransform(res: AxiosResponse<Result>, options: RequestOptions) {
    const { t } = useI18n();
    const { isTransformResponse, isReturnNativeResponse } = options;
    // 是否返回原生响应头 比如：需要获取响应头时使用该属性
    if (isReturnNativeResponse) {
      return res;
    }
    // 不进行任何处理，直接返回
    // 用于页面代码可能需要直接获取code，data，message这些信息时开启
    if (!isTransformResponse) {
      return res.data;
    }
    // 错误的时候返回
    const { data } = res;
    if (!data) {
      // return '[HTTP] Request has no return value';
      throw new Error(t('sys.api.apiRequestFailed'));
    }
    //  这里 code，result，message为 后台统一的字段，需要在 types.ts内修改为项目自己的接口返回格式
    const { code, result, message } = data;
    // 这里逻辑可以根据项目进行修改
    const hasSuccess = data && Reflect.has(data, 'code') && code === ResultEnum.SUCCESS;
    if (hasSuccess) {
      return result;
    }
    // 在此处根据自己项目的实际情况对不同的code执行不同的操作
    // 如果不希望中断当前请求，请return数据，否则直接抛出异常即可
    let timeoutMsg = '';
    switch (code) {
      case ResultEnum.TIMEOUT:
        timeoutMsg = t('sys.api.timeoutMessage');
        UserStorage.setToken(undefined);
        UserService.logout(true);
        break;
      default:
        if (message) {
          timeoutMsg = message;
        }
    }
    // errorMessageMode=‘modal’的时候会显示modal错误弹窗，而不是消息提示，用于一些比较重要的错误
    // errorMessageMode='none' 一般是调用时明确表示不希望自动弹出错误提示
    if (options.errorMessageMode === 'modal') {
      createErrorModal({ title: t('sys.api.errorTip'), content: timeoutMsg });
    } else if (options.errorMessageMode === 'message') {
      createMessage.error(timeoutMsg).then();
    } else {
      throw new Error(timeoutMsg || t('sys.api.apiRequestFailed'));
    }
    // throw new Error(timeoutMsg || t('sys.api.apiRequestFailed'));
  }

  public static beforeRequest(config: AxiosRequestConfig) {
    // TOKEN 验证与续时
    let continueTime = true;
    for (const ur of IGNORE_RESOURCES) {
      // @ts-ignore
      if (config.url.search(new RegExp(ur)) > 0) {
        continueTime = false;
      }
    }
    if (continueTime) {
      UserService.validateJwtToken(true);
    }
  }
}
